# -*- coding: utf-8 -*-

import signal
import subprocess
import threading
import time
import os
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

import naja_atra.utils.logger as logger

logger.set_level("DEBUG")
_logger = logger.get_logger("dev")


ROOT = os.path.dirname(os.path.abspath(__file__))
START_SERVER_CMD = [f"{ROOT}/venv/bin/python3", "main.py"]
WATCH_DIR = f"{ROOT}/demo"


dev_running = True
dev_server_thread = None
dev_server_process = None


class MyEventHandler(FileSystemEventHandler):
    def restart_dev_server(self, event):
        _logger.info(f"Receive event {event}")
        path: str = event.src_path
        if event.is_directory:
            _logger.info("Ignore directory changes.")
            return
        if path.find("__pycache__") >= 0:
            _logger.info("Ignore file changes in `__pycache__` folder ")
            return
        global dev_server_process
        stop_server_dev()
        while dev_server_process:
            time.sleep(1)
        _logger.info("stop server success! start it again.")
        start_server_dev()
        while not dev_server_process:
            time.sleep(1)
        _logger.info("start server success!")

    def on_moved(self, event):
        self.restart_dev_server(event)

    def on_deleted(self, event):
        self.restart_dev_server(event)

    def on_modified(self, event):
        self.restart_dev_server(event)


def start_server_process():
    global dev_server_process
    dev_server_process = subprocess.Popen(START_SERVER_CMD,
                                          bufsize=1,
                                          stdout=subprocess.PIPE,
                                          stderr=subprocess.STDOUT,
                                          text=True,
                                          encoding="utf-8",
                                          errors="replace")
    while True:
        line = dev_server_process.stdout.readline().rstrip()
        if not line:
            break
        print(f"[Process#{dev_server_process.pid}]>> {line}")
    dev_server_process = None


def start_server_dev():
    if not dev_running:
        _logger.warning("Server is asked to stop, not start it again. ")
        return
    _logger.info("Start server in background.")
    global dev_server_thread
    dev_server_thread = threading.Thread(
        target=start_server_process, daemon=True)
    dev_server_thread.start()


def stop_server_dev():
    global dev_server_thread
    _logger.info("Stop server and wait.")
    if dev_server_process:
        _logger.info(f"kill {dev_server_process.pid}")
        subprocess.run(["kill", f"{dev_server_process.pid}"])
    if dev_server_thread:
        dev_server_thread.join()
        dev_server_thread = None


def on_sig_term(signum, frame):
    _logger.info(f"Receive signal [{signum}], stop dev server now...")
    global dev_running
    dev_running = False
    stop_server_dev()


def run_as_dev():
    start_server_dev()
    event_handler = MyEventHandler()
    observer = Observer()
    observer.schedule(event_handler, WATCH_DIR, recursive=True)
    observer.daemon = True
    observer.start()
    try:
        while dev_running:
            time.sleep(1)
    finally:
        observer.stop()
        observer.join()


def main():
    signal.signal(signal.SIGTERM, on_sig_term)
    signal.signal(signal.SIGINT, on_sig_term)
    run_as_dev()


if __name__ == "__main__":
    main()
